home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 …ember: Reference Library / Apple Developer Reference Library (December 1999) (Disk 1).iso / pc / technical documentation / develop / develop issue 28 / develop issue 28 code / sketch / source / appleevent / oslclassdocument.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-25  |  44.0 KB  |  1,773 lines

  1. /****************************************************************************
  2.  * 
  3.  * OSLClassDocument.c
  4.  * 
  5.  * OSL support for the cDocument Apple Event Registry object
  6.  *
  7.  ****************************************************************************/
  8.  
  9. #include <stdio.h>            // for sprintf()
  10.  
  11. #include  "OSLClassDocument.h"
  12.  
  13. #include "AERCoreSuite.h"
  14. #include "AppleEvent.h"
  15. #include "OSLHelpers.h"
  16.  
  17. #include "Documents.h"
  18. #include "DocumentADT.h"
  19. #include "DocumentHelpers.h"
  20.  
  21. #include "ElementADT.h"
  22. #include "ElementHelpers.h"
  23.  
  24. #include "Assertion.h"
  25. #include "Sounds.h"
  26. #include "StringUtils.h"    // for PToCString(). etc.
  27.  
  28. // ----------------------------------------------------------------------------
  29. //                      Core Suite Object Event handlers
  30. // ----------------------------------------------------------------------------
  31.  
  32. static OSErr HandleClose        (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply);
  33. static OSErr HandleCount        (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply);
  34. static OSErr HandleDataSize    (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply);
  35. static OSErr HandleDelete        (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply);
  36. static OSErr HandleDuplicate    (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply);
  37. static OSErr HandleExists        (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply);
  38. static OSErr HandleGetData        (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply);
  39. static OSErr HandleMake            (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply);
  40. static OSErr HandleMove            (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply);
  41. static OSErr HandleOpen            (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply);
  42. static OSErr HandlePrint        (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply);
  43. static OSErr HandleQuit            (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply);
  44. static OSErr HandleSave            (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply);
  45. static OSErr HandleSetData        (AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply);
  46.  
  47. // ----------------------------------------------------------------------------
  48. // Do the application-specific part of the work
  49.  
  50. static OSErr DoClose                                        (AEDesc *token, const AEDesc *saving, AEDesc *savingIn);
  51. static OSErr DoSave                                        (AEDesc *token, const AEDesc *inFile, AEDesc *asType);
  52.  
  53. // ----------------------------------------------------------------------------
  54. //                      Core Suite Object Accessor functions
  55. // ----------------------------------------------------------------------------
  56.  
  57. static OSErr 
  58. MakeNewObject(
  59.             const DescType         objectToCreate,
  60.             const DescType         insertionPosition,
  61.             const AEDesc         *token,
  62.             const AEDesc         *ptrToWithData, 
  63.             const AEDesc         *ptrToWithProperties,
  64.             AppleEvent             *reply);
  65.  
  66. static pascal OSErr 
  67. DocumentFromApplicationAccessor(         
  68.                     DescType        desiredClass,
  69.             const AEDesc*        containerToken,
  70.                     DescType        containerClass,
  71.                     DescType        keyForm,
  72.             const AEDesc*        keyData,
  73.                     AEDesc*        resultToken,
  74.                     long             refCon);
  75.  
  76. static OSErr 
  77. PropertyFromListAccessor(
  78.                      DescType        desiredClass,
  79.              const AEDesc*        containerToken,
  80.                      DescType        containerClass,
  81.                      DescType        keyForm,
  82.              const AEDesc*        keyData,
  83.                      AEDesc*        resultToken,
  84.                      long             refCon);
  85.                                          
  86. static OSErr 
  87. PropertyFromObjectAccessor(
  88.                      DescType        desiredClass,
  89.              const AEDesc*        containerToken,
  90.                      DescType        containerClass,
  91.                      DescType        keyForm,
  92.              const AEDesc*        keyData,
  93.                      AEDesc*        resultToken,
  94.                      long             refCon);
  95.  
  96. static OSErr        GetDataFromList        (AEDesc *srcList, AEDesc *desiredTypes, AEDesc *dstList);
  97. static OSErr        GetDataFromObject        (AEDesc *token,   AEDesc *desiredTypes, AEDesc *data);
  98.  
  99. static OSErr        SetDataForList            (AEDesc *token, AEDesc *data);
  100. static OSErr        SetDataForObject        (AEDesc *token, AEDesc *data);
  101.  
  102. static Boolean        CanGetProperty            (DescType property);
  103. static Boolean        CanSetProperty            (DescType property);
  104. static OSErr         SetProperties            (DocumentReference document, AEDesc *propertyRecord);
  105.  
  106. static OSErr         ProcessFormRelativePostition    (const AEDesc* anchorToken, const AEDesc *keyData, DocumentReference *document);
  107.  
  108. static long         GetDocumentIndex        (DocumentReference document);
  109.  
  110. /*****************************************************************************
  111.  * 
  112.  * DocumentEventDispatcher
  113.  *
  114.  *    Handles all OSL messages that cDocument should handle
  115.  * 
  116.  *****************************************************************************/
  117.  
  118. OSErr
  119. DocumentEventDispatcher(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply, long refcon)
  120. {
  121.     #pragma unused (refcon)
  122.  
  123.     OSErr error = noErr;
  124.     
  125.     AEEventID    eventID;
  126.     OSType        typeCode;
  127.     Size            actualSize = 0L;
  128.     
  129.     // Get the event ID
  130.     
  131.     error = AEGetAttributePtr(appleEvent, 
  132.                                       keyEventIDAttr, 
  133.                                       typeType, 
  134.                                       &typeCode, 
  135.                                       (Ptr)&eventID, 
  136.                                       sizeof(eventID), 
  137.                                       &actualSize);
  138.  
  139.     if (error != noErr) {
  140.         return error;
  141.     }
  142.     
  143.     switch (eventID) {
  144.     
  145.         case kAEClone:
  146.             error = HandleDuplicate(token, appleEvent, reply);
  147.             break;
  148.             
  149.         case kAEClose:
  150.             error = HandleClose(token, appleEvent, reply);
  151.             break;
  152.             
  153.         case kAECountElements:
  154.             error = HandleCount(token, appleEvent, reply);
  155.             break;
  156.             
  157.         case kAECreateElement:
  158.             error = HandleMake(token, appleEvent, reply);
  159.             break;
  160.             
  161.         case kAEDelete:
  162.             error = HandleDelete(token, appleEvent, reply);
  163.             break;
  164.             
  165.         case kAEDoObjectsExist:
  166.             error = HandleExists(token, appleEvent, reply);
  167.             break;
  168.             
  169.         case kAEGetData:
  170.             error = HandleGetData(token, appleEvent, reply);
  171.             break;
  172.             
  173.         case kAEGetDataSize:
  174.             error = HandleDataSize(token, appleEvent, reply);
  175.             break;
  176.             
  177.         case kAEMove:
  178.             error = HandleMove(token, appleEvent, reply);
  179.             break;
  180.             
  181.         case kAEOpen:
  182.             error = HandleOpen(token, appleEvent, reply);
  183.             break;
  184.             
  185.         case kAEPrint:
  186.             error = HandlePrint(token, appleEvent, reply);
  187.             break;
  188.             
  189.         case kAEQuitApplication:
  190.             error = HandleQuit(token, appleEvent, reply);
  191.             break;
  192.             
  193.         case kAESave:
  194.             error = HandleSave(token, appleEvent, reply);
  195.             break;
  196.             
  197.         case kAESetData:
  198.             error = HandleSetData(token, appleEvent, reply);
  199.             break;
  200.  
  201.         default:
  202.             error = errAEEventNotHandled;
  203.             break;
  204.     }
  205.     
  206.     if (error != noErr && reply->descriptorType != typeNull)
  207.         PutReplyErrorNumber(reply, error);
  208.  
  209.     return error;
  210. }
  211.  
  212. #pragma mark -
  213. // ----------------------------------------------------------------------------
  214. //                      Core Suite Object Event handlers
  215. // ----------------------------------------------------------------------------
  216. // "close <DocRef> saving <yes|no|ask> saving in <FileRef>"
  217.  
  218. static OSErr 
  219. HandleClose(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply)
  220. {
  221.     #pragma unused (reply)
  222.  
  223.     OSErr         error     = noErr;
  224.     
  225.     DescType        typeCode = 0L;
  226.     
  227.     AEDesc        saving    = {typeNull, nil};
  228.     AEDesc        savingIn = {typeNull, nil};
  229.     
  230.     AEDesc      *ptrToSaving    = NULL;
  231.     AEDesc      *ptrToSavingIn = NULL;
  232.     
  233.     // Extract the [saving yes/no/ask] optional parameter, if present
  234.     
  235.     error = AEGetParamDesc(appleEvent, keyAESaveOptions, typeWildCard, &saving);
  236.     
  237.     if (error == noErr)
  238.         ptrToSaving = &saving;
  239.     else if (error == errAEDescNotFound)
  240.        error = noErr;
  241.     else
  242.         goto Cleanup;
  243.     
  244.     // Extract the [saving in <alias>] optional parameter, if present
  245.     
  246.     error = AEGetParamDesc(appleEvent, keyAEFile, typeFSS, &savingIn);
  247.     
  248.     if (error == noErr)
  249.         ptrToSavingIn = &savingIn;
  250.     else if (error == errAEDescNotFound)
  251.        error = noErr;
  252.     else
  253.         goto Cleanup;
  254.  
  255.     // Check for any required parameters we may have missed
  256.     
  257.     error = CheckForUnusedParameters(appleEvent);
  258.     if (error != noErr)
  259.         goto Cleanup;
  260.         
  261.     // Now, do the application-related work
  262.  
  263.     // Now, close one or more items
  264.  
  265.     if (TokenContainsTokenList(token))
  266.     {
  267.         AEDescList  flatList     = {typeNull, nil};
  268.         AEDesc        singleToken = {typeNull, nil};
  269.         long            numItems;
  270.         long            itemNum;
  271.         AEKeyword    keyword;
  272.         
  273.         error = AECreateList(NULL, 0L, false, &flatList);
  274.         if (error == noErr)
  275.             error = FlattenAEList(token, &flatList);
  276.             
  277.         if (error == noErr)
  278.         {
  279.             error = AECountItems(&flatList, &numItems);
  280.             if (error == noErr || numItems > 0)
  281.             {
  282.                 for (itemNum = 1; itemNum <= numItems; itemNum++)
  283.                 {
  284.                    error = AEGetNthDesc(&flatList, itemNum, typeWildCard, &keyword, &singleToken);
  285.                    
  286.                     if (error == noErr)
  287.                         error = DoClose(&singleToken, ptrToSaving, ptrToSavingIn);
  288.                     else
  289.                         break;
  290.                         
  291.                     AEDisposeDesc(&singleToken);
  292.                 }
  293.             }
  294.         }
  295.         
  296.         AEDisposeDesc(&flatList);
  297.         AEDisposeDesc(&singleToken);
  298.     }
  299.     else
  300.     {
  301.         error = DoClose(token, ptrToSaving, ptrToSavingIn);
  302.     }
  303.  
  304. Cleanup:
  305.  
  306.     AEDisposeDesc(&saving);
  307.     AEDisposeDesc(&savingIn);
  308.         
  309.     return error;
  310. }
  311.  
  312. // ----------------------------------------------------------------------------
  313. // This is called to count the various things contained inside a document object
  314. // Eg., "count rectangles in document 1"
  315. // OR, if we receive a list of document, we could be counting documents
  316. // that satisfy a whose statement
  317.  
  318. static OSErr 
  319. HandleCount(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply)
  320. {
  321.     OSErr                    error                 = noErr;    
  322.     long                    numberOfObjects    = 0L;
  323.     DescType                objectClass;
  324.     DocumentReference document                = nil;
  325.         
  326.     // Get the class of object that we will count
  327.  
  328.     error = GetObjectClassFromAppleEvent(appleEvent, &objectClass);
  329.  
  330.     // Make sure we got & handled all of the required parameters
  331.     
  332.     if (error == noErr)
  333.         error = CheckForUnusedParameters(appleEvent);
  334.  
  335.     // If we receive a list, then we're counting documents via a whose clause
  336.  
  337.     if (TokenContainsTokenList(token))
  338.     {
  339.         AEDesc tempToken = {typeNull, nil};
  340.         
  341.         error = GetFirstNonListToken(token, &tempToken);
  342.         
  343.         if (error == noErr && tempToken.descriptorType == cDocument)
  344.             error = AECountItems(token, &numberOfObjects);
  345.         
  346.         AEDisposeDesc(&tempToken);
  347.     }
  348.     else
  349.     {
  350.         if (error == noErr)
  351.             error = GetDocumentReferenceFromToken(token, &document);
  352.         
  353.         if (error == noErr)
  354.         {
  355.             switch (objectClass)
  356.             {
  357.                 default:
  358.                     numberOfObjects = CountElementsByClass(GetDocumentElementList(document), objectClass);
  359.                     break;
  360.             }
  361.         }
  362.     }
  363.  
  364.     // Now return the result in the reply apple event
  365.         
  366.     if (error == noErr && reply != NULL && reply->descriptorType != typeNull)
  367.     {        
  368.         error = AEPutParamPtr(reply, keyAEResult, typeLongInteger, (Ptr)&numberOfObjects, sizeof(long));
  369.     }
  370.  
  371.     return error;    
  372. }
  373.  
  374. // ----------------------------------------------------------------------------
  375. // This is called to get the size of the data for an object in a document
  376.  
  377. static OSErr 
  378. HandleDataSize(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply)
  379. {
  380.     OSErr     error = noErr;
  381.     AEDesc    data     = {typeNull, nil};    
  382.     long        size  = 0L;
  383.     
  384.     // First, get the data
  385.     error = HandleGetData(token, appleEvent, reply);
  386.     
  387.     // now, extract it from the reply
  388.     
  389.     if (error == noErr)
  390.         error = AEGetKeyDesc(reply, keyDirectObject, typeWildCard, &data);
  391.         
  392.     if (error == noErr)
  393.     {
  394.         if (data.dataHandle != nil)
  395.         {
  396.             size = GetHandleSize(data.dataHandle);
  397.         }                         
  398.         error = AEPutParamPtr(reply, 
  399.                                      keyAEResult, 
  400.                                      typeLongInteger, 
  401.                                      (Ptr)&size, 
  402.                                      sizeof(long));
  403.     }
  404.  
  405.     AEDisposeDesc(&data);
  406.     
  407.     return error;
  408.  
  409. }
  410.  
  411. // ----------------------------------------------------------------------------
  412. // "Delete document" is treated as equivalent to "close document"
  413.  
  414. static OSErr 
  415. HandleDelete(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply)
  416. {
  417.     OSErr error = HandleClose(token, appleEvent, reply);
  418.     
  419.     return error;
  420. }
  421.  
  422. // ----------------------------------------------------------------------------
  423. // Handles messages like "duplicate document 1"
  424. // ••• should handle the the options [to location referece] parameter also •••
  425.  
  426. static OSErr 
  427. HandleDuplicate(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply)
  428. {
  429.     #pragma unused (token, appleEvent, reply)
  430.  
  431.     return errAEEventNotHandled;
  432. }
  433.  
  434. // ----------------------------------------------------------------------------
  435. // If document 1 exists...
  436. // The AEResolve() function in AERCoreSuite.c will already have filtered
  437. // out all cases where the object did not exist, so this function should
  438. // always return TRUE.
  439.  
  440. static OSErr 
  441. HandleExists(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply)
  442. {
  443.     #pragma unused (token, appleEvent)
  444.  
  445.     OSErr error         = noErr;
  446.     Boolean foundIt    = true;
  447.  
  448.     if (error == noErr && reply != NULL && reply->descriptorType != typeNull)
  449.     {
  450.         error = AEPutParamPtr(reply, 
  451.                          keyAEResult, 
  452.                          typeBoolean, 
  453.                          (Ptr)&foundIt, 
  454.                          sizeof(Boolean));
  455.     }
  456.         
  457.     return error;
  458. }
  459.  
  460. // ----------------------------------------------------------------------------
  461.  
  462. static OSErr 
  463. HandleGetData(AEDesc *tokenOrTokenList, const AppleEvent *appleEvent, AppleEvent *reply)
  464. {
  465.     OSErr             error             = noErr;    
  466.     AEDesc            data                 = {typeNull, nil};
  467.     AEDesc            desiredTypes   = {typeNull, nil};
  468.     
  469.     AEGetParamDesc(appleEvent, keyAERequestedType, typeAEList, &desiredTypes);
  470.     
  471.     error = GetDataFromDocument(tokenOrTokenList, &desiredTypes, &data);
  472.  
  473.     if (error == noErr && reply->descriptorType != typeNull)
  474.         error = AEPutKeyDesc(reply, keyDirectObject, &data);
  475.         
  476.     AEDisposeDesc(&data);
  477.     AEDisposeDesc(&desiredTypes);
  478.     
  479.     return error;
  480. }
  481.  
  482. // ----------------------------------------------------------------------------
  483. // Make a new document
  484.  
  485. static OSErr 
  486. HandleMake(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply)
  487. {
  488.     OSErr             error                     = noErr;
  489.     
  490.     OSType            typeCode;
  491.     Size                actualSize;
  492.  
  493.     DescType            newObjClass                = typeNull;
  494.     DescType            insertionPos            = typeNull;
  495.     
  496.     AEDesc            insertionLoc            = {typeNull, nil};
  497.     AEDesc            objectSpec                = {typeNull, nil};
  498.  
  499.     long                documentNumber         = 0L;
  500.  
  501.     DocumentReference document             = nil;
  502.  
  503.     // Optional parameters
  504.     AEDesc             withData                    = {typeNull, nil};
  505.     AEDesc             withProperties           = {typeNull, nil};
  506.  
  507.     AEDesc             *ptrToWithData            = NULL;
  508.     AEDesc           *ptrToWithProperties = NULL;
  509.  
  510.     newObjClass = **(DescType**)(token->dataHandle);
  511.     
  512.     
  513.     //    For Create Element, the object specifier is contained in  
  514.     //    a typeInsertionLoc record instead of in a direct parameter. 
  515.     // We coerce the insertionLoc record into an AERecord so we can extract the fields.     
  516.     // Notice that this is a REQUIRED parameter, but we give it a default behavior
  517.     // by creating a new document as the frontmost document
  518.     
  519.     error = AEGetParamDesc(appleEvent,                 // Extract as a AERecord
  520.                                   keyAEInsertHere, 
  521.                                   typeAERecord, 
  522.                                   &insertionLoc);
  523.  
  524.     if (error == errAEDescNotFound)
  525.     {
  526.         insertionPos = kAEBeginning;
  527.         error        = noErr;
  528.     }
  529.     else if (error == noErr)
  530.     {
  531.  
  532.         // Get the enumerated insertion location (at end, in front, before, after, replace.)
  533.         
  534.         error = AEGetKeyPtr(&insertionLoc, 
  535.                                       keyAEPosition,             // insertion location
  536.                                     typeEnumeration, 
  537.                                     &typeCode, 
  538.                                     (Ptr)&insertionPos,
  539.                                    sizeof(insertionPos), 
  540.                                    &actualSize);
  541.                                    
  542.         //    Extract and resolve the object specifier from the insertion location record.
  543.         // In a case like "make new document before document 2",
  544.         // the ospec will resolve to "document 2"
  545.                  
  546.         error = AEGetKeyDesc(&insertionLoc, 
  547.                                     keyAEObject, 
  548.                                     typeWildCard, 
  549.                                     &objectSpec);
  550.     }
  551.                 
  552.     // if there was a object specifier in the insertion location (eg, "before document 1",
  553.     //   then we call AEResolve() to get a token for it,
  554.     // Otherwise, is was something like "at end" or "at beginning", which is also OK, 
  555.     //   then deal with it correctly later.
  556.         
  557.     if (objectSpec.descriptorType == typeNull) 
  558.     {
  559.         AEDisposeDesc(token);            // destroy it's old representation, toke will no be null descriptor
  560.     }
  561.     else
  562.     {
  563.         error = AEResolve(&objectSpec, 
  564.                              kAEIDoMinimum, 
  565.                              token);            // token will contain info about the object to insert before, after, etc.
  566.         if (error != noErr) 
  567.         {
  568.             goto CleanUp;
  569.         }
  570.     }
  571.     
  572.     // Extract the optional parameters from the AppleEvent
  573.     
  574.     // ----- [with data ....] -----
  575.     
  576.     error = AEGetParamDesc(appleEvent, 
  577.                                   keyAEData,
  578.                                   typeWildCard,
  579.                                   &withData);
  580.     if (error != noErr && error != errAEDescNotFound) 
  581.         goto CleanUp;
  582.     
  583.     if (error == errAEDescNotFound)
  584.         error = noErr;
  585.     else    
  586.         ptrToWithData = &withData;
  587.     
  588.     // ----- [with properties {property: value, ...}] -----
  589.     
  590.     error = AEGetParamDesc(appleEvent, 
  591.                                   keyAEPropData, 
  592.                                   typeWildCard, 
  593.                                   &withProperties);
  594.     if (error != noErr && error != errAEDescNotFound) 
  595.         goto CleanUp;
  596.  
  597.     if (error == errAEDescNotFound)
  598.         error = noErr;
  599.     else    
  600.         ptrToWithProperties = &withProperties;
  601.         
  602.     // Finally, use the token and other parameters to create & initialize the object
  603.  
  604.     if (error == noErr)
  605.     {
  606.         error = MakeNewObject(newObjClass, insertionPos, token, ptrToWithData, ptrToWithProperties, reply);
  607.     }
  608.     
  609. CleanUp:    
  610.  
  611.     AEDisposeDesc(&insertionLoc);
  612.     AEDisposeDesc(&objectSpec);
  613.     AEDisposeDesc(&withData);
  614.     AEDisposeDesc(&withProperties);
  615.  
  616.     return error;
  617. }
  618.  
  619. // ----------------------------------------------------------------------------
  620.  
  621. static OSErr 
  622. HandleMove(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply)
  623. {
  624.     #pragma unused (token, appleEvent, reply)
  625.  
  626.     OSErr error = errAEEventNotHandled;
  627.     
  628.     return error;
  629. }
  630.  
  631. // ----------------------------------------------------------------------------
  632. // class cDocument always refers to an OPEN document - so this handler would
  633. // not seem to be needed here
  634.  
  635. static OSErr 
  636. HandleOpen(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply)
  637. {
  638.     #pragma unused (token, appleEvent, reply)
  639.  
  640.     OSErr error = errAEEventNotHandled;
  641.     
  642.     return error;
  643. }
  644.  
  645. // ----------------------------------------------------------------------------
  646.  
  647. static OSErr 
  648. HandlePrint(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply)
  649. {
  650.     #pragma unused (token, appleEvent, reply)
  651.  
  652.     OSErr error = errAEEventNotHandled;
  653.     
  654.     return error;
  655. }
  656.  
  657. // ----------------------------------------------------------------------------
  658.  
  659. static OSErr 
  660. HandleQuit(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply)
  661. {
  662.     #pragma unused (token, appleEvent, reply)
  663.  
  664.     OSErr error = errAEEventNotHandled;
  665.     
  666.     return error;
  667. }
  668.  
  669. // ----------------------------------------------------------------------------
  670. // "save <DocRef> in <FileRef> as <FileTypeConstant>"
  671.  
  672. static OSErr 
  673. HandleSave(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply)
  674. {
  675.     #pragma unused (reply)
  676.  
  677.     OSErr         error     = noErr;
  678.     
  679.     DescType        typeCode = 0L;
  680.     
  681.     AEDesc        inFile     = {typeNull, nil};
  682.     AEDesc        asType   = {typeNull, nil};
  683.     
  684.     AEDesc      *ptrToInFile    = NULL;
  685.     AEDesc      *ptrToAsType   = NULL;
  686.     
  687.     // "The keyInteractLevelAttr attribute determines whether the 
  688.     // server app can interact with the user when handling the event"
  689.     
  690.     // error = AEGetAttributePtr(appleEvent, keyInteractLevelAttr, typeType, &);
  691.     
  692.     
  693.     // Extract the "in <FileRef>" optional parameter
  694.     
  695.     error = AEGetParamDesc(appleEvent, keyAEFile, typeFSS, &inFile);
  696.     
  697.     if (error == noErr)
  698.         ptrToInFile = &inFile;
  699.     else if (error == errAEDescNotFound)
  700.        error = noErr;
  701.     else
  702.         goto Cleanup;
  703.  
  704.     // Extract the "as <FileType>" optional parameter
  705.     
  706.     error = AEGetParamDesc(appleEvent, keyAEFileType, typeType, &asType);
  707.     
  708.     if (error == noErr)
  709.         ptrToAsType = &asType;
  710.     else if (error == errAEDescNotFound)
  711.        error = noErr;
  712.     else
  713.         goto Cleanup;
  714.  
  715.     // Check for any required parameters we may have missed
  716.     
  717.     error = CheckForUnusedParameters(appleEvent);
  718.     if (error != noErr)
  719.         goto Cleanup;
  720.         
  721.     // Now, do the application-related work
  722.  
  723.     error = DoSave(token, ptrToInFile, ptrToAsType);
  724.  
  725. Cleanup:
  726.  
  727.     AEDisposeDesc(&inFile);
  728.     AEDisposeDesc(&asType);
  729.         
  730.     return error;
  731. }
  732.  
  733. // ----------------------------------------------------------------------------
  734.  
  735. static OSErr 
  736. HandleSetData(AEDesc *token, const AppleEvent *appleEvent, AppleEvent *reply)
  737. {
  738.     #pragma unused (reply)
  739.  
  740.     OSErr             error          = noErr;    
  741.     AEDesc            data           = {typeNull, nil};
  742.     
  743.     DescType             propertyCode;
  744.     DescType            objectClass;
  745.     
  746.     switch (token->descriptorType)
  747.     {
  748.         case typeAEList:
  749.             error = ExtractKeyDataParameter(appleEvent, &data);
  750.             if (error == noErr)
  751.                 error = SetDataForList(token, &data);
  752.             break;
  753.                 
  754.         case cProperty:
  755.             propertyCode     = ExtractPropertyCodeFromToken(token);
  756.             objectClass    = ExtractObjectClassFromToken(token);
  757.             if (CanSetProperty(propertyCode))
  758.             {
  759.                 error = ExtractKeyDataParameter(appleEvent, &data);
  760.                 if (error == noErr)
  761.                     error = SetDataForObject(token, &data);
  762.             }
  763.             else
  764.             {
  765.                 error = errAENotModifiable;
  766.             }
  767.             break;
  768.             
  769.         default:
  770.             error = errAENotModifiable;
  771.             break;
  772.     }
  773.         
  774.     AEDisposeDesc(&data);
  775.     
  776.     return error;
  777. }
  778.  
  779.  
  780.  
  781. #pragma mark -
  782. // -----------------------------------------------------------------------------
  783. //                                                Object Accessors
  784. //------------------------------------------------------------------------------
  785.  
  786. OSErr 
  787. InstallDocumentAccessors(void)
  788. {
  789.  
  790.     OSErr error;
  791.     
  792.     error = AEInstallObjectAccessor(cDocument, 
  793.                                               typeNull, 
  794.                                               NewOSLAccessorProc(DocumentFromApplicationAccessor), 
  795.                                               0L, 
  796.                                               false);
  797.  
  798.     // although documents can't contain other documents, 
  799.     // we need this accessor to support formRelativePostion,
  800.     // which sends us one document as a "container" and asks us to find
  801.     // either the document before or after that document
  802.  
  803.     error = AEInstallObjectAccessor(cDocument, 
  804.                                               cDocument, 
  805.                                               NewOSLAccessorProc(DocumentFromApplicationAccessor), 
  806.                                               0L, 
  807.                                               false);
  808.  
  809.     if (error == noErr)
  810.         error = AEInstallObjectAccessor(cProperty, 
  811.                                                   cDocument, 
  812.                                                   NewOSLAccessorProc(PropertyFromDocumentAccessor), 
  813.                                                   0L, 
  814.                                                   false);
  815.  
  816.     return error;
  817. }
  818.  
  819. #pragma mark -
  820. //------------------------------------------------------------------------------
  821. //    Retrieve the Document from the null container by the key form
  822.  
  823. static pascal OSErr 
  824. DocumentFromApplicationAccessor(         
  825.                 DescType        desiredClass,        // cDocument
  826.         const AEDesc*        containerToken,    // null container
  827.                 DescType        containerClass,   // cApplication
  828.                 DescType        keyForm,
  829.         const AEDesc*        keyData,
  830.                 AEDesc*        resultToken,        // specified Document is returned in result
  831.                 long             refCon)
  832. {
  833.     #pragma unused (containerToken, containerClass, refCon)
  834.  
  835.     OSErr                    error                = noErr;
  836.     DocumentReference    document           = nil;
  837.     
  838.     DescType                keyDataType     = keyData->descriptorType;
  839.  
  840.     long                    index;
  841.     long                    numItems;
  842.     Boolean                wantsAllItems    = false;
  843.     
  844.     AEDesc                 startObject     =    {typeNull, nil};    // These are used to resolve formRange
  845.     AEDesc                 stopObject        =     {typeNull, nil};
  846.  
  847.     Str63                    documentName;
  848.  
  849.     CoreTokenRecord     token;
  850.     InitCoreTokenRecord(&token);
  851.     
  852.     numItems = CountDocuments(GetDocumentList());
  853.  
  854.     switch (keyForm) 
  855.     {
  856.         case formName:                                                    // Document by name
  857.             {
  858.                 if (DescToPString(keyData, documentName, 63) != noErr)
  859.                 {
  860.                     error = errAECoercionFail;
  861.                 }
  862.                 else
  863.                 {
  864.                     document = GetDocumentByName(documentName);
  865.                     if (document == nil)
  866.                         error = errAENoSuchObject;
  867.                 }
  868.             }
  869.             break;
  870.         
  871.         case formAbsolutePosition:                                    // Document by number
  872.             error = NormalizeAbsoluteIndex(keyData, &index, numItems, &wantsAllItems);
  873.             if ((error == noErr) && (wantsAllItems == false))
  874.             {
  875.                 document = GetDocumentByIndex(index);
  876.                 if (document == nil)
  877.                     error = errAEIllegalIndex;
  878.             }
  879.             break;    
  880.         
  881.         case formRelativePosition:
  882.             error = ProcessFormRelativePostition(containerToken, keyData, &document);
  883.             break;    
  884.         
  885.         case formRange:
  886.             switch (keyDataType)
  887.             {        
  888.                 case typeRangeDescriptor:
  889.                     error = ProcessFormRange((AEDesc *)keyData, &startObject, &stopObject);
  890.                     if (error == noErr)
  891.                     {
  892.                         DescType startType = ExtractDispatchClassFromToken(&startObject);
  893.                         DescType stopType  = ExtractDispatchClassFromToken(&stopObject);
  894.      
  895.                         if (startType != cDocument || stopType != cDocument)
  896.                             error = errAEWrongDataType;
  897.                     }
  898.                     break;
  899.  
  900.                 default:
  901.                     error = errAEWrongDataType;
  902.                     break;    
  903.             }
  904.             break;    
  905.  
  906.         default:
  907.             error = errAEEventNotHandled;
  908.             break;
  909.     }
  910.     
  911.     // if user asked for all items, and there aren't any,
  912.     // we'll be kind and return an empty list.
  913.  
  914.     if (wantsAllItems && (error == errAENoSuchObject || error == errAEIllegalIndex))
  915.     {
  916.         error = AECreateList(NULL, 0, false, (AEDescList*)resultToken);
  917.         goto CleanUp;
  918.     }
  919.  
  920.     // fill in the result token
  921.  
  922.     if (error == noErr)
  923.     {
  924.         token.dispatchClass   = cDocument;
  925.         token.objectClass         = cDocument;
  926.         token.propertyCode    = typeNull;
  927.  
  928.         if (wantsAllItems)
  929.         {                        
  930.             error = AECreateList(NULL, 0, false, (AEDescList*)resultToken);
  931.             
  932.             if (error == noErr)
  933.             {
  934.                 for (index = 1; index <= numItems; index++)
  935.                 {
  936.                     document = GetDocumentByIndex(index);
  937.                     if (document == nil)
  938.                         goto CleanUp;
  939.                         
  940.                     token.documentNumber = GetDocumentNumber(document);
  941.                     
  942.                     error = AEPutPtr(resultToken, 0, desiredClass, &token, sizeof(token));
  943.                     if (error != noErr)
  944.                         goto CleanUp;
  945.                 }
  946.             }
  947.         }
  948.         else if (keyForm == formRange)
  949.         {            
  950.             DocumentReference    beginDocument;
  951.             DocumentReference endDocument;
  952.             long                    beginIndex;
  953.             long                    endIndex;
  954.             
  955.             error = GetDocumentReferenceFromToken(&startObject, &beginDocument);
  956.             if (error != noErr)
  957.                 goto CleanUp;
  958.             beginIndex = GetDocumentIndex(beginDocument);
  959.  
  960.             error = GetDocumentReferenceFromToken(&stopObject, &endDocument);
  961.             if (error != noErr)
  962.                 goto CleanUp;
  963.             endIndex = GetDocumentIndex(endDocument);
  964.                                     
  965.             error = AECreateList(NULL, 0, false, (AEDescList*)resultToken);
  966.             if (error != noErr)
  967.                 goto CleanUp;
  968.                 
  969.             if (beginIndex > endIndex) // swap elements
  970.             {
  971.                 DocumentReference temp;
  972.                 
  973.                 temp               = beginDocument;
  974.                 beginDocument = endDocument;
  975.                 endDocument   = temp;
  976.             }
  977.             
  978.             document = beginDocument;
  979.             while (document != nil)
  980.             {
  981.                 token.documentNumber = GetDocumentNumber(document);
  982.                 
  983.                 error = AEPutPtr(resultToken, 0, desiredClass, &token, sizeof(token));
  984.                 if (error != noErr)
  985.                     goto CleanUp;
  986.  
  987.                 if (document == endDocument)
  988.                     break;
  989.                 document = GetNextFrontDocument(GetDocumentList(), document);
  990.             }
  991.         }
  992.         else
  993.         {
  994.             token.documentNumber = GetDocumentNumber(document);
  995.             error = AECreateDesc(desiredClass, &token, sizeof(token), resultToken);
  996.         }
  997.     }
  998.  
  999. CleanUp:
  1000.     
  1001.     AEDisposeDesc(&startObject);
  1002.     AEDisposeDesc(&stopObject);
  1003.         
  1004.     return error;
  1005. }
  1006.  
  1007. #pragma mark -
  1008. //----------------------------------------------------------------------------------
  1009. //                                        Document Property Accessor
  1010. //----------------------------------------------------------------------------------
  1011. // Handles properties from document token or list of document tokens
  1012. //
  1013. // NOTE: The container can be either a single token, or a list of tokens
  1014. // 
  1015. //----------------------------------------------------------------------------------
  1016.  
  1017. pascal OSErr 
  1018. PropertyFromDocumentAccessor(     
  1019.                     DescType        desiredClass,
  1020.             const AEDesc*        containerToken,
  1021.                     DescType        containerClass,
  1022.                     DescType        keyForm,
  1023.             const AEDesc*        keyData,
  1024.                     AEDesc*        resultToken,
  1025.                     long             refCon)
  1026. {
  1027.     OSErr        error            = noErr;
  1028.  
  1029.     if (TokenContainsTokenList((AEDescList*)containerToken) == false)
  1030.     {
  1031.         error = PropertyFromObjectAccessor(desiredClass, containerToken, containerClass, keyForm, keyData, resultToken, refCon);
  1032.     }
  1033.     else
  1034.     {
  1035.         error = AECreateList(NULL, 0L, false, resultToken);
  1036.         if (error == noErr)
  1037.             error = PropertyFromListAccessor(desiredClass, containerToken, containerClass, keyForm, keyData, resultToken, refCon);
  1038.     }
  1039.     
  1040.     return error;
  1041. }
  1042.  
  1043. //----------------------------------------------------------------------------------
  1044.  
  1045. static OSErr 
  1046. PropertyFromListAccessor(
  1047.                  DescType        desiredClass,
  1048.         const AEDesc*        containerToken,
  1049.                 DescType        containerClass,
  1050.                 DescType        keyForm,
  1051.         const AEDesc*        keyData,
  1052.                 AEDesc*        resultToken,
  1053.                 long             refCon)
  1054. {
  1055.     OSErr            error        = noErr;
  1056.     long            itemNum;
  1057.     long            numItems;
  1058.     DescType        keyword;
  1059.     AEDesc        srcItem     = {typeNull, nil};
  1060.     AEDesc        dstItem     = {typeNull, nil};
  1061.     
  1062.     error = AECountItems((AEDescList*)containerToken, &numItems);
  1063.     if (error != noErr)
  1064.         goto CleanUp;
  1065.         
  1066.     for (itemNum = 1; itemNum <= numItems; itemNum++)
  1067.     {
  1068.        error = AEGetNthDesc(containerToken, itemNum, typeWildCard, &keyword, &srcItem);
  1069.         if (error != noErr)
  1070.             goto CleanUp;
  1071.         
  1072.         if (TokenContainsTokenList(&srcItem) == false)
  1073.         {
  1074.             error = PropertyFromObjectAccessor(desiredClass, &srcItem, containerClass, keyForm, keyData, &dstItem, refCon);
  1075.         }
  1076.         else
  1077.         {
  1078.             error = AECreateList(NULL, 0L, false, &dstItem);
  1079.             if (error == noErr)
  1080.                 error = PropertyFromListAccessor(desiredClass, &srcItem, containerClass, keyForm, keyData, &dstItem, refCon);
  1081.         }
  1082.         
  1083.         if (error != noErr)
  1084.             goto CleanUp;
  1085.  
  1086.         error = AEPutDesc(resultToken, itemNum, &dstItem);
  1087.         if (error != noErr)
  1088.             goto CleanUp;
  1089.                 
  1090.         AEDisposeDesc(&srcItem);
  1091.         AEDisposeDesc(&dstItem);
  1092.     }
  1093.     
  1094. CleanUp:
  1095.  
  1096.     AEDisposeDesc(&srcItem);
  1097.     AEDisposeDesc(&dstItem);
  1098.  
  1099.     return error;
  1100. }
  1101.  
  1102. //----------------------------------------------------------------------------------
  1103. //    Return a token representing the property for the containing window.  
  1104. // The token is returned with the property and window reference.
  1105. //----------------------------------------------------------------------------------
  1106.  
  1107. static OSErr 
  1108. PropertyFromObjectAccessor(
  1109.                     DescType        desiredType,            // cProperty
  1110.             const     AEDesc*        containerToken,
  1111.                       DescType        containerClass,         // cDocument
  1112.                       DescType        keyForm,                    // formPropertyID
  1113.           const    AEDesc*        keyData,                    // dataHandle points to which property
  1114.                       AEDesc*        resultToken,            // contains our CoreTokenRecord in token.dataHandle
  1115.                       long             refCon     )
  1116. {
  1117.     #pragma unused (containerClass, keyForm, refCon)
  1118.  
  1119.     OSErr                        error;    
  1120.     DescType                    requestedProperty;
  1121.  
  1122.     error = AEDuplicateDesc(containerToken, resultToken);
  1123.     if (error != noErr)
  1124.         return error;
  1125.         
  1126.     requestedProperty = **(DescType**)(keyData->dataHandle);
  1127.     
  1128.     if (requestedProperty == kAEAll)
  1129.         requestedProperty = pProperties;
  1130.  
  1131.     if (CanGetProperty(requestedProperty) || CanSetProperty(requestedProperty))
  1132.     {
  1133.         resultToken->descriptorType = desiredType;
  1134.         (**(CoreTokenHandle)(resultToken->dataHandle)).propertyCode = requestedProperty;
  1135.     }
  1136.     else
  1137.     {
  1138.         error = errAEEventNotHandled;
  1139.     }
  1140.     
  1141.     return error;
  1142. }
  1143.  
  1144. #pragma mark -
  1145. // -------------------------------------------------------------------------------------------
  1146. //
  1147. //   GetDataFromDocument
  1148. //
  1149. // Given a token that contains information about a document object, access the object
  1150. // to extract the relevant data, and return it to the caller in the "data" parameter.
  1151. //
  1152. // PUBLIC: also called from the ObjectComparison callback function
  1153. //
  1154. // The first parameter can be a single token or a list of tokens
  1155. // The second parameter is NULL or a list of preferred types for the return data
  1156. //
  1157. // -------------------------------------------------------------------------------------------
  1158.  
  1159. OSErr
  1160. GetDataFromDocument(AEDesc *tokenOrTokenList, AEDesc *desiredTypes, AEDesc *data)
  1161. {
  1162.     OSErr error = noErr;
  1163.     
  1164.     if (TokenContainsTokenList(tokenOrTokenList) == false)
  1165.     {
  1166.         error = GetDataFromObject(tokenOrTokenList, desiredTypes, data);
  1167.     }
  1168.     else
  1169.     {
  1170.         error = AECreateList(NULL, 0L, false, data);
  1171.         if (error == noErr)
  1172.             error = GetDataFromList(tokenOrTokenList, desiredTypes, data);
  1173.     }
  1174.     
  1175.     return error;
  1176. }
  1177.  
  1178. // -------------------------------------------------------------------------------------------
  1179. //
  1180. //   GetDataFromList
  1181. //
  1182. // -------------------------------------------------------------------------------------------
  1183.  
  1184. static OSErr
  1185. GetDataFromList(AEDesc *srcList, AEDesc *desiredTypes, AEDesc *dstList)
  1186. {
  1187.     OSErr            error        = noErr;
  1188.     long            itemNum;
  1189.     long            numItems;
  1190.     DescType        keyword;
  1191.     AEDesc        srcItem     = {typeNull, nil};
  1192.     AEDesc        dstItem     = {typeNull, nil};
  1193.         
  1194.     error = AECountItems((AEDescList*)srcList, &numItems);
  1195.     if (error != noErr)
  1196.         goto CleanUp;
  1197.         
  1198.     for (itemNum = 1; itemNum <= numItems; itemNum++)
  1199.     {
  1200.        error = AEGetNthDesc(srcList, itemNum, typeWildCard, &keyword, &srcItem);
  1201.         if (error != noErr)
  1202.             goto CleanUp;
  1203.         
  1204.         if (TokenContainsTokenList(&srcItem) == false)
  1205.         {
  1206.             error = GetDataFromObject(&srcItem, desiredTypes, &dstItem);  // Get data from single item
  1207.         }
  1208.         else
  1209.         {
  1210.             error = AECreateList(NULL, 0L, false, &dstItem);
  1211.             if (error == noErr)
  1212.                 error = GetDataFromList(&srcItem, desiredTypes, &dstItem);
  1213.         }
  1214.         if (error != noErr)
  1215.             goto CleanUp;
  1216.  
  1217.         error = AEPutDesc(dstList, itemNum, &dstItem);
  1218.         if (error != noErr)
  1219.             goto CleanUp;
  1220.                 
  1221.         AEDisposeDesc(&srcItem);
  1222.         AEDisposeDesc(&dstItem);
  1223.     }
  1224.     
  1225. CleanUp:
  1226.  
  1227.     AEDisposeDesc(&srcItem);
  1228.     AEDisposeDesc(&dstItem);
  1229.  
  1230.     return error;
  1231. }
  1232.  
  1233. //----------------------------------------------------------------------------------
  1234. //    GetDataFromObject
  1235. //
  1236. // Extract the document reference from a token and then return the property the user requested
  1237. //
  1238. //----------------------------------------------------------------------------------
  1239.  
  1240.  
  1241. static OSErr 
  1242. GetDataFromObject(AEDesc *token, AEDesc *desiredTypes, AEDesc *data)
  1243. {
  1244.     #pragma unused (desiredTypes)
  1245.  
  1246.     OSErr                    error                    = noErr;
  1247.     Boolean                usePropertyCode    = false;    
  1248.     DocumentReference document             = nil;
  1249.             
  1250.     DescType                aType                   = cDocument;
  1251.     Str63                 documentName;
  1252.     Boolean                 isModified;
  1253.     
  1254.     error = GetDocumentReferenceFromToken(token, &document);
  1255.     if (error != noErr || document == nil)
  1256.         goto CleanUp;
  1257.  
  1258.     GetDocumentName(document, documentName);                        
  1259.     isModified = DocumentIsModified(document);                        
  1260.  
  1261.     usePropertyCode = ExtractUsePropertyCodeFromToken(token);
  1262.     
  1263.     if (usePropertyCode)
  1264.     {
  1265.         DescType propertyCode = ExtractPropertyCodeFromToken(token);
  1266.         
  1267.         switch (propertyCode)
  1268.         {
  1269.             case pProperties:
  1270.                 error = AECreateList(NULL, 0L, true, data);
  1271.                 if (error != noErr)
  1272.                     goto CleanUp;
  1273.  
  1274.                 error = AEPutKeyPtr(data, pObjectType,    typeType,         &aType,                    sizeof(DescType));
  1275.                 error = AEPutKeyPtr(data, pName,         typeChar,         &documentName[1],     documentName[0]);
  1276.                 error = AEPutKeyPtr(data, pIsModified, typeBoolean,     &isModified,             sizeof(Boolean));
  1277.                 break;
  1278.                 
  1279.             case pBestType:
  1280.             case pClass:
  1281.             case pDefaultType:
  1282.             case pObjectType:
  1283.                 error = AECreateDesc(typeType, &aType, sizeof(DescType), data);
  1284.                 break;
  1285.                 
  1286.             case pName:
  1287.                 error = AECreateDesc(typeChar, &documentName[1], documentName[0], data);
  1288.                 break;
  1289.                 
  1290.             case pIsModified:
  1291.                 error = AECreateDesc(typeBoolean, &isModified, sizeof(Boolean), data);
  1292.                 break;
  1293.                 
  1294.             deafult:
  1295.                 error = errAECantSupplyType;
  1296.         }
  1297.     }
  1298.     
  1299. CleanUp:
  1300.  
  1301.     return error;
  1302. }
  1303.  
  1304. #pragma mark -
  1305. // -------------------------------------------------------------------------------------------
  1306. //
  1307. //   SetDataFromDocumentTokenList
  1308. //
  1309. // Given a token that contains a list of cWindow tokens,
  1310. // walk the list recursively to set the data for each token in the list
  1311. //
  1312. // -------------------------------------------------------------------------------------------
  1313.  
  1314. static OSErr
  1315. SetDataForList(AEDesc *token, AEDesc *data)
  1316. {
  1317.     OSErr             error          = noErr;    
  1318.     AEDesc              tempToken      = {typeNull, nil};
  1319.     
  1320.     long                numItems;
  1321.     long                itemNum;
  1322.     AEKeyword        keyword;
  1323.         
  1324.     if (TokenContainsTokenList(token) == false)
  1325.     {
  1326.         error = SetDataForObject(token, data);
  1327.     }
  1328.     else
  1329.     {
  1330.         error = AECountItems((AEDescList*)token, &numItems);
  1331.         if (error != noErr)
  1332.             goto CleanUp;
  1333.         
  1334.         for (itemNum = 1; itemNum <= numItems; itemNum++)
  1335.         {
  1336.            error = AEGetNthDesc((AEDescList*)token, itemNum, typeWildCard, &keyword, &tempToken);
  1337.             if (error != noErr)
  1338.                 goto CleanUp;
  1339.             
  1340.             if (TokenContainsTokenList(&tempToken) == false)
  1341.             {
  1342.                 error = SetDataForObject(&tempToken, data);          // Set data from single item
  1343.             }
  1344.             else
  1345.             {
  1346.                 error = SetDataForList(&tempToken, data);     // Recurse sublist
  1347.             }
  1348.             if (error != noErr)
  1349.                 goto CleanUp;
  1350.                     
  1351.             AEDisposeDesc(&tempToken);
  1352.         }
  1353.     }
  1354.  
  1355. CleanUp:
  1356.     
  1357.     AEDisposeDesc(&tempToken);
  1358.     
  1359.     return error;
  1360. }
  1361.  
  1362. //----------------------------------------------------------------------------------
  1363. //
  1364. //    SetDataForObject()
  1365. //
  1366. //----------------------------------------------------------------------------------
  1367. // Assumption: HandleSetData() has already filtered out all attempts
  1368. // to write to a read-only property.
  1369.  
  1370. // Extract the document reference from a token
  1371. // and then store the data we received into the target property
  1372.  
  1373. static OSErr 
  1374. SetDataForObject(AEDesc *token, AEDesc *data)
  1375. {
  1376.  
  1377.     OSErr                    error                        = noErr;
  1378.         
  1379.     Boolean                usePropertyCode;
  1380.     DescType                propertyCode;
  1381.     
  1382.     DocumentReference document                    = nil;
  1383.     
  1384.     AEDesc                 propertyRecord         = {typeNull, nil};
  1385.  
  1386.     usePropertyCode = ExtractUsePropertyCodeFromToken(token);
  1387.     
  1388.     error = GetDocumentReferenceFromToken(token, &document);
  1389.         
  1390.     if (usePropertyCode == false)
  1391.     {
  1392.         error = errAEWriteDenied;
  1393.     }
  1394.     else
  1395.     {
  1396.         propertyCode = ExtractPropertyCodeFromToken(token);
  1397.         
  1398.         if (data->descriptorType == typeAERecord)
  1399.         {        
  1400.             error = SetProperties(document, data);
  1401.         }
  1402.         else    // Build a record with one property
  1403.         {
  1404.             error = AECreateList(NULL, 0L, true, &propertyRecord);
  1405.             if (error != noErr)
  1406.                 goto CleanUp;
  1407.             
  1408.             error = AEPutKeyDesc(&propertyRecord, propertyCode, data);
  1409.             if (error != noErr)
  1410.                 goto CleanUp;
  1411.         
  1412.             error = SetProperties(document, &propertyRecord);
  1413.         }
  1414.     }
  1415.  
  1416. CleanUp:
  1417.  
  1418.     AEDisposeDesc(&propertyRecord);
  1419.  
  1420.     return error;
  1421. }
  1422.  
  1423.  
  1424. //----------------------------------------------------------------------------------
  1425. //                                           SetProperties
  1426. //----------------------------------------------------------------------------------
  1427. // Set an object's properties from the record we receive
  1428.  
  1429. static OSErr 
  1430. SetProperties(DocumentReference document, AEDesc *propertyRecord)
  1431. {
  1432.     OSErr                 error             = noErr;
  1433.     OSErr                 ignoreError     = noErr;
  1434.         
  1435.     long                     numProperties     = 0L;
  1436.         
  1437.     AEDesc                 data                 = {typeNull, nil};
  1438.     
  1439.     Str63                 documentName;
  1440.     
  1441.     Boolean                documentWasModified = false;
  1442.     
  1443.     if (propertyRecord == NULL || propertyRecord->descriptorType != typeAERecord)
  1444.     {
  1445.         error = errAEWrongDataType;
  1446.         goto CleanUp;
  1447.     }
  1448.                 
  1449.     error = AECountItems(propertyRecord, &numProperties);
  1450.         
  1451.     if (error != noErr || numProperties <= 0)
  1452.         goto CleanUp;
  1453.         
  1454.     // pName
  1455.     
  1456.     ignoreError = AEGetKeyDesc(propertyRecord, pName, typeChar, &data);
  1457.     if (ignoreError != errAEDescNotFound)
  1458.     {
  1459.         error = DescToPString(&data, documentName, 63);
  1460.         if (error == noErr)
  1461.         {
  1462.             SetDocumentName(document, documentName);
  1463.             documentWasModified = true;
  1464.         }
  1465.  
  1466.         AEDisposeDesc(&data);
  1467.     }
  1468.  
  1469.     if (error == noErr && documentWasModified)
  1470.         MarkDocumentAsChanged(document);
  1471.  
  1472. CleanUp:
  1473.  
  1474.     return error;
  1475. }
  1476.  
  1477. //----------------------------------------------------------------------------------
  1478. //                                       Token Inserter
  1479. //----------------------------------------------------------------------------------
  1480. // Note: token can contain the results of an AEResolve() call (ie, an object spec)
  1481. //       OR it can contain a null descriptor {typeNull, null} if insertion location
  1482. //           object was specified.
  1483.  
  1484. static OSErr 
  1485. MakeNewObject(
  1486.          const DescType     objectToCreate, 
  1487.          const DescType     insertionPosition, 
  1488.          const AEDesc         *token, 
  1489.          const AEDesc         *ptrToWithData, 
  1490.          const AEDesc         *ptrToWithProperties,
  1491.                 AppleEvent *reply)
  1492. {
  1493.     #pragma unused (objectToCreate, ptrToWithData)
  1494.  
  1495.     OSErr                 error         = noErr;
  1496.     DocumentReference oldDocument = nil;
  1497.     DocumentReference newDocument = nil;
  1498.     
  1499.     if (token->descriptorType == typeNull)
  1500.         oldDocument = GetFrontDocument(GetDocumentList());
  1501.     else
  1502.         error = GetDocumentReferenceFromToken(token, &oldDocument);
  1503.     
  1504.     if (error == noErr)
  1505.     {        
  1506.         newDocument = MakeNewDocument(NULL);
  1507.         error = DocumentError();
  1508.                     
  1509.         // By default, Documents are created at the end of the list
  1510.         // If insertionPosition == kAEBeginning, then all is OK,
  1511.         
  1512.         if (error == noErr)
  1513.         {
  1514.             switch (insertionPosition)
  1515.             {
  1516.                 case kAEBeginning:
  1517.                     // default behavior creates element as frontmost object
  1518.                     break;
  1519.                     
  1520.                 case kAEEnd:
  1521.                 case kAEBefore:
  1522.                 case kAEAfter:
  1523.                 case kAEReplace:
  1524.                 default:
  1525.                     break;    
  1526.             }            
  1527.         }
  1528.         
  1529.         // Now, apply properties, if we received any properties to set,
  1530.         // then they are in a AERecord where 
  1531.         
  1532.         if (ptrToWithProperties != NULL)
  1533.         {
  1534.             long numProperties = 0;
  1535.             error = AECountItems(ptrToWithProperties, &numProperties);
  1536.         
  1537.             if (error == noErr && numProperties > 0)
  1538.             {
  1539.                 AEDesc propertyDesc = {typeNull, nil};
  1540.                 
  1541.                 // pName
  1542.                 
  1543.                 error = AEGetKeyDesc(ptrToWithProperties, pName, typeChar, &propertyDesc);
  1544.                 if (error != errAEDescNotFound)
  1545.                 {
  1546.                     Str63 documentName;
  1547.                     DescToPString(&propertyDesc, documentName, 63);
  1548.                     SetDocumentName(newDocument, documentName);
  1549.                     AEDisposeDesc(&propertyDesc);
  1550.                 }
  1551.                 
  1552.                 if (error == errAEDescNotFound)
  1553.                     error = noErr;
  1554.             }
  1555.         }
  1556.     }
  1557.     
  1558.     // return a reference to the new document in the AppleEvent reply parameter
  1559.     
  1560.     if (error == noErr && newDocument != nil)
  1561.     {
  1562.         AEDesc ospec = {typeNull, nil};
  1563.  
  1564.         error = CreateDocumentOSpec(newDocument, &ospec);
  1565.         
  1566.         if (error == noErr)
  1567.         {
  1568.             AEPutParamDesc(reply, keyDirectObject, &ospec);
  1569.         }
  1570.     
  1571.         AEDisposeDesc(&ospec);
  1572.     }
  1573.  
  1574. CleanUp:
  1575.  
  1576.     return error;
  1577. }
  1578.  
  1579. #pragma mark -
  1580. //----------------------------------------------------------------------------------
  1581. //            Application-Specific code triggered by a similarly-named HandleXXX()
  1582. //----------------------------------------------------------------------------------
  1583.  
  1584. static OSErr 
  1585. DoClose(AEDesc *token, const AEDesc *saving, AEDesc *savingIn)
  1586. {
  1587.     #pragma unused (saving, savingIn)
  1588.  
  1589.     OSErr                 error             = noErr;
  1590.     DocumentReference document;
  1591.         
  1592.     error = GetDocumentReferenceFromToken(token, &document);
  1593.         
  1594.     if (error == noErr && document != nil)
  1595.         DestroyDocument(document);
  1596.     else
  1597.         error = errAEEventNotHandled;
  1598.  
  1599.     return error;
  1600. }
  1601.  
  1602. //----------------------------------------------------------------------------------
  1603. //            Application-Specific code triggered by a similarly-named HandleXXX()
  1604. //----------------------------------------------------------------------------------
  1605.  
  1606. static OSErr 
  1607. DoSave(AEDesc *token, const AEDesc *inFile, AEDesc *asType)
  1608. {
  1609.     #pragma unused (token, inFile, asType)
  1610.     return errAEEventNotHandled;
  1611. }
  1612.  
  1613.  
  1614.  
  1615. #pragma mark -
  1616. //----------------------------------------------------------------------------------
  1617.  
  1618. static Boolean
  1619. CanGetProperty(DescType property)
  1620. {
  1621.     Boolean    result = false;
  1622.     
  1623.     switch (property)
  1624.     {
  1625.         // Properties we can get:
  1626.         
  1627.         case pBestType:
  1628.         case pClass:
  1629.         case pDefaultType:
  1630.         case pObjectType:
  1631.         
  1632.         case pName:
  1633.         case pProperties:
  1634.         case pIsModified:
  1635.             result = true;
  1636.             break;
  1637.             
  1638.         // Properties we can't get:
  1639.         default:
  1640.             result = false;
  1641.             break;
  1642.     }
  1643.  
  1644.     return result;
  1645. }
  1646.  
  1647. //----------------------------------------------------------------------------------
  1648.  
  1649. static Boolean
  1650. CanSetProperty(DescType property)
  1651. {
  1652.     Boolean    result = false;
  1653.     
  1654.     switch (property)
  1655.     {
  1656.         // Properties we can set:
  1657.         
  1658.         case pName:
  1659.             result = true;
  1660.             break;
  1661.             
  1662.         // Properties we can't set:
  1663.  
  1664.         default:
  1665.         case pBestType:
  1666.         case pClass:
  1667.         case pDefaultType:
  1668.         case pObjectType:
  1669.         
  1670.         case pProperties:
  1671.         case pIsModified:
  1672.             result = false;
  1673.             break;
  1674.     }
  1675.  
  1676.     return result;
  1677. }
  1678.  
  1679.  
  1680. #pragma mark -
  1681.  
  1682. // -------------------------------------------------------------------------------------------
  1683.  
  1684. static OSErr 
  1685. ProcessFormRelativePostition(const AEDesc* anchorToken, const AEDesc *keyData, DocumentReference *document)
  1686. {
  1687.     OSErr                    error = noErr;
  1688.     
  1689.     DescType             positionEnum;    
  1690.  
  1691.     DocumentReference anchorDocument;
  1692.     DocumentReference relativeDocument = nil;
  1693.     
  1694.     *document = nil;
  1695.     
  1696.     error = GetDocumentReferenceFromToken(anchorToken, &anchorDocument);
  1697.  
  1698.     if (error == noErr)
  1699.     {
  1700.     
  1701.         switch (keyData->descriptorType)
  1702.         {
  1703.            case typeEnumerated:
  1704.                 if (DescToDescType((AEDesc*)keyData, &positionEnum) != noErr)
  1705.                 {
  1706.                     error = errAECoercionFail;
  1707.                 }
  1708.                 else
  1709.                 {
  1710.                     switch (positionEnum)
  1711.                     {
  1712.                         case kAENext:                        // get the document behind the anchor
  1713.                             *document = GetPreviousDocument(anchorDocument);
  1714.                             if (*document == nil)
  1715.                                 error = errAENoSuchObject;
  1716.                             break;
  1717.                             
  1718.                         case kAEPrevious:                    // get the document in front of the anchor
  1719.                             *document = GetNextDocument(anchorDocument);
  1720.                             if (*document == nil)
  1721.                                 error = errAENoSuchObject;
  1722.                             break;
  1723.                             
  1724.                         default:
  1725.                             error = errAEEventNotHandled;
  1726.                             break;
  1727.                     }
  1728.                 }
  1729.                 break;
  1730.                 
  1731.             default:
  1732.                 error = errAECoercionFail;
  1733.                 break;
  1734.         }
  1735.     }
  1736.     
  1737.     return error;
  1738. }
  1739.  
  1740. //----------------------------------------------------------------------------------
  1741. //    Returns the index (front to back) for the specified document
  1742. //----------------------------------------------------------------------------------
  1743.  
  1744. static long 
  1745. GetDocumentIndex(DocumentReference document)
  1746. {
  1747.     DocumentList        list        = GetDocumentList();
  1748.     DocumentReference    iter       = GetFrontDocument(list);
  1749.     
  1750.     Boolean             foundIt  = false;
  1751.     long                    i            = 1L;
  1752.             
  1753.     while (iter != nil)
  1754.     {
  1755.         if (iter == document)
  1756.         {
  1757.             foundIt = true;
  1758.             break;
  1759.         }
  1760.             
  1761.         iter = (DocumentReference) GetNextFrontDocument(list, iter);
  1762.         i++;
  1763.     }
  1764.     
  1765.     if (!foundIt)
  1766.         i = 0;
  1767.  
  1768.     return i;
  1769. }
  1770.  
  1771. // -------------------------------------------------------------------------------------------
  1772.  
  1773.